package customer

import (
	"context"
	"errors"
	"fmt"
	"go.manyji.com/lib/mysql"
	"go.manyji.com/lib/util/convert"
	stdRand "math/rand"
	"sieve_admin_server/app/dao"
	"sieve_admin_server/app/dao/business_price_scheme"
	"sieve_admin_server/app/dao/business_type"
	"sieve_admin_server/app/dao/user"
	"sieve_admin_server/app/schema"
	schemaCustomer "sieve_admin_server/app/schema/customer"
	"sieve_admin_server/app/server"
	serviceLog "sieve_admin_server/app/service/logger"
	serviceSys "sieve_admin_server/app/service/sys"
	"sieve_admin_server/pkg/util"
	"strconv"
	"strings"
	"time"

	"github.com/google/wire"
	"go.manyji.com/lib/hash"
	"go.manyji.com/lib/log"
	"go.manyji.com/lib/rand"
)

var (
	UserSet = wire.NewSet(wire.Struct(new(UserSrv), "*"))
)

var (
	adminAccount = user.User{
		ID:      1,
		Account: "admin",
		Passwd:  GeneratePasswd(12),
	}
)

type UserSrv struct {
	SieveConfigSrv          *SieveConfigSrv
	SieveSourceConfigRepo   *dao.SieveSourceConfigRepo
	BusinessPriceSchemeRepo *dao.BusinessPriceSchemeRepo
	UserRepo                *dao.UserRepo
	Trans                   *dao.Trans
	BusinessTypeRepo        *dao.BusinessTypeRepo
	BusinessSrv             *serviceLog.BusinessSrv
	BusinessRecordRepo      *dao.BusinessRecordRepo
	RoleSrv                 *serviceSys.RoleSrv
	RoleRepo                *dao.RoleRepo
}

func UpdateAdminAccount(roleId uint64, args ...interface{}) {
	adminAccount.RoleId = roleId
}

func GeneratePasswd(count int) string {

	var (
		configCh = []struct {
			start byte
			end   byte
		}{
			{
				'0',
				'9',
			},
			{
				'A',
				'Z',
			},
			{
				'a',
				'z',
			},
		}
		chs           []byte
		passwordCount = count

		passwd string
	)

	for _, v := range configCh {
		for i := v.start; i <= v.end; i++ {
			chs = append(chs, i)
		}
	}

	stdRand.Seed(time.Now().UnixNano())
	chsLength := len(chs)

	// 1. 生成密码
	for i := 0; i < passwordCount; i++ {
		passwd += string(chs[stdRand.Intn(chsLength)])
	}

	return passwd
}

// 创建或者更新公司员工
func (a *UserSrv) CreateOrUpdateStaffUser(ctx context.Context, uid uint64, roleTy int) error {

	var staffName string
	staffName = server.GetUserInfo(int(uid)).Name

	resp, err := a.GetByUID(ctx, uid)
	if err != nil && err.Error() != "record not  found" {
		return errors.New(fmt.Sprintf("获取用户信息失败:%+v", err))
	}

	var account = fmt.Sprintf("%v", uid)
	// 如果为空，可能是 登录的工号是超级管理员(配置文件有配置)，但是没有分配给这个应用
	if staffName != "" {
		account = staffName
	}

	adminRoleId, err := a.RoleSrv.CreateRole(ctx, 1)
	if err != nil {
		return errors.New(fmt.Sprintf("创建管理员角色失败:%+v", err))
	} else {
		UpdateAdminAccount(uint64(adminRoleId))
	}

	if resp != nil {
		// 原先是管理员，现在是业务员，需要变更角色
		if resp.RoleId == uint64(adminRoleId) && roleTy == 2 {
			err = a.UserRepo.Update(context.Background(), map[string]interface{}{
				"role_id": a.RoleSrv.GetSalespersonRole().ID,
			}, map[string]interface{}{
				"id": uid,
			})
			if err != nil {
				return errors.New(fmt.Sprintf("更新用户(%v)角色失败:%+v", uid, err))
			}
		}

		// 原先是业务员的，现在是管理员
		if a.RoleSrv.IsSalespersonRole(resp.RoleId) && roleTy == 1 {
			err = a.UserRepo.Update(context.Background(), map[string]interface{}{
				"role_id": a.RoleSrv.GetAdminRole().ID,
			}, map[string]interface{}{
				"id": uid,
			})
			if err != nil {
				return errors.New(fmt.Sprintf("更新用户(%v)角色失败:%+v", uid, err))
			}
		}
		return nil
	}

	item := map[string]interface{}{}
	if roleTy == 1 {
		item = map[string]interface{}{
			"id":            uid,
			"account":       account,
			"passwd":        GeneratePasswd(12),
			"role_id":       adminRoleId,
			"leader_id":     adminAccount.ID,
			"top_leader_id": adminAccount.ID,
		}
	}
	if roleTy == 2 {
		item = map[string]interface{}{
			"id":            uid,
			"account":       account,
			"passwd":        GeneratePasswd(12),
			"role_id":       a.RoleSrv.GetSalespersonRole().ID,
			"leader_id":     adminAccount.ID,
			"top_leader_id": adminAccount.ID,
		}
	}

	return a.Create(ctx, adminAccount.ID, item)
}

func (a *UserSrv) UpdateLastRecharge(ctx context.Context, uid uint64, lastRecharge int64) error {

	var (
		updateKeys = map[string]interface{}{
			"last_recharge": lastRecharge,
			"updated_at":    lastRecharge,
		}
		queryKeys = map[string]interface{}{
			"id": uid,
		}
	)
	return a.UserRepo.Update(ctx, updateKeys, queryKeys)
}

func (a *UserSrv) GetByAccountAndPasswd(ctx context.Context, account, password string) (*user.User, error) {

	var (
		tableName = user.User{}
		querySQL  = fmt.Sprintf(`
	SELECT * FROM %v 
	WHERE account = '%v'
	AND passwd = '%v'
	AND deleted = 0
`, tableName.TableName(), account, password)
	)

	req, err := a.UserRepo.QueryRaw(ctx, querySQL, user.User{})
	if err != nil {
		return nil, err
	}

	if req == nil {
		return nil, errors.New(fmt.Sprintf("record not  found"))
	}
	return req[0].(*user.User), nil
}

func (a *UserSrv) GetByUID(ctx context.Context, uid uint64, args ...interface{}) (*user.User, error) {

	var (
		tableName = user.User{}
		querySQL  = fmt.Sprintf(`SELECT * FROM %v WHERE id = %v AND deleted = 0 `, tableName.TableName(), uid)
		cr        bool
	)

	if len(args) == 1 {

		// 表示是否是当前读，用 FOR UPDATE 语句指定
		if args[0].(bool) {
			cr = true
			querySQL += " FOR UPDATE"
		}
	}

	var req []interface{}

	// 如果查询条件附带了 FOR UPDATE，由于查询会立刻返回，所以需要多调用几次，
	if cr {
		var (
			retryCount    = 5
			retryInterval = 100 * time.Millisecond
		)

		// 获取被充值人的账户余额
		for i := 0; i < retryCount; i++ {
			_req, err := a.UserRepo.QueryRaw(ctx, querySQL, user.User{})
			if err == nil {
				req = _req
				break
			}

			if isLockError(err) || isDeadlineExceededError(err) {
				time.Sleep(retryInterval)
				continue
			}

			return nil, err
		}
	} else {

		_req, err := a.UserRepo.QueryRaw(ctx, querySQL, user.User{})
		if err != nil {
			return nil, err
		}
		req = _req
	}

	if req == nil {
		return nil, errors.New(fmt.Sprintf("record not  found"))
	}
	return req[0].(*user.User), nil
}

func (a *UserSrv) Get(ctx context.Context, uid, leaderId uint64, name string) (*user.User, error) {

	var (
		tableName = user.User{}
		querySQL  = fmt.Sprintf(`
	SELECT * FROM %v 
	WHERE account = '%v'
	AND leader_id = %v
	AND creator = %v
	AND deleted = 0
`, tableName.TableName(), name, leaderId, uid)
	)

	req, err := a.UserRepo.QueryRaw(ctx, querySQL, user.User{})
	if err != nil {
		return nil, err
	}

	if req == nil {
		return nil, errors.New(fmt.Sprintf("record not  found"))
	}
	return req[0].(*user.User), nil
}

func (a *UserSrv) GetByName(ctx context.Context, name string) (*user.User, error) {

	var (
		tableName = user.User{}
		querySQL  = fmt.Sprintf(`
	SELECT * FROM %v 
	WHERE account = '%v'
	AND deleted = 0
`, tableName.TableName(), name)
	)

	req, err := a.UserRepo.QueryRaw(ctx, querySQL, user.User{})
	if err != nil {
		return nil, err
	}

	if req == nil {
		return nil, errors.New(fmt.Sprintf("record not  found"))
	}
	return req[0].(*user.User), nil
}

func GenPwdHash(pwd string) string {
	salt := hash.MD5([]byte(rand.RandStr(16) + time.Now().String()))
	return hash.SHA256([]byte(pwd+salt)) + salt
}

func isValidFileName(fileName string) bool {
	forbiddenChars := []string{"/", "\\", ":", "*", "?", "\"", "<", ">", "|"}

	for _, char := range forbiddenChars {
		if strings.Contains(fileName, char) {
			return false
		}
	}

	return true
}
func (a *UserSrv) getDefaultSieveSourceConfig() ([]string, error) {

	var (
		querySQL = fmt.Sprintf(`
			SELECT
				business_type_configuration.*
			FROM
			    sieve_source_config
			INNER JOIN 
			    business_type_configuration ON business_type_configuration.sieve_source_config_id = sieve_source_config.id AND business_type_configuration.deleted = 0
			WHERE %v AND sieve_source_config.deleted = 0 
`, "`default` = 1")
	)

	resp, err := a.BusinessTypeRepo.QueryRaw(context.Background(), querySQL, business_type.BusinessTypeConfiguration{})
	if err != nil {
		return nil, err
	}

	var (
		cids      []string
		removeDup = map[uint64]struct{}{}
	)
	// 如果有多个相同的 business_type_configuration.id 做去重处理
	for _, v := range resp {
		vv := v.(*business_type.BusinessTypeConfiguration)
		if _, ok := removeDup[vv.ID]; ok {
			continue
		}
		removeDup[vv.ID] = struct{}{}
	}

	for v := range removeDup {
		cids = append(cids, fmt.Sprintf("%v", v))
	}

	return cids, nil
}
func (a *UserSrv) Create(ctx context.Context, uid uint64, item map[string]interface{}) error {

	if v, ok := item["account"]; ok {
		//var leaderId uint64
		//if v, ok := item["leader_id"]; ok {
		//	leaderId = v.(uint64)
		//} else {
		//	leaderId = uid
		//}
		//fmt.Println(leaderId)
		//
		// 同一个 leader_id 下面创建的用户名唯一
		//if respUser, err := a.Get(ctx, uid, leaderId, item["account"].(string)); err == nil && respUser != nil {
		//	return errors.New(fmt.Sprintf("用户已存在"))
		//}

		if !isValidFileName(v.(string)) {
			return errors.New(fmt.Sprintf("用户名不能包含下列任何字符：\n\t\\ / : * ? < > |"))
		}
	}

	//util.Struct2Slice(schemaCustomer.BusinessPriceQueryRsp{}, "json", "business_price_scheme")

	if resp, err := a.BusinessPriceSchemeRepo.Query(ctx, map[string]interface{}{
		"def": 1,
	}, schema.PaginationParam{
		OnlyData: true,
	}, util.Struct2Slice(business_price_scheme.BusinessPriceScheme{}, "json", "business_price_scheme")); resp != nil {
		if err != nil {
			return errors.New(fmt.Sprintf("获取默认业务方案失败"))
		}

		if len(resp.(map[string]interface{})["list"].([]interface{})) == 0 {
			return errors.New(fmt.Sprintf("获取默认业务方案失败"))
		}
		id := resp.(map[string]interface{})["list"].([]interface{})[0].(*business_price_scheme.BusinessPriceScheme).ID
		item["business_price_id"] = id
	}

	//if _, ok := item["business_price_id"]; !ok {
	//	return errors.New(fmt.Sprintf("'业务方案'为必填项"))
	//}

	if respUser, err := a.GetByName(ctx, item["account"].(string)); err == nil && respUser != nil {
		return errors.New(fmt.Sprintf("用户已存在"))
	}

	var (
		now = time.Now().Unix()
		def = map[string]interface{}{
			"creator":    uid,
			"create_at":  now,
			"updated_at": now,
		}
	)

	for k, v := range def {
		item[k] = v
	}

	var leaderId uint64
	// 添加用户的时候，如果没有指定上级，那么自动将创建人指定为上级
	if v, ok := item["leader_id"]; !ok {
		item["leader_id"] = uid
		leaderId = uid
	} else {
		leaderId = v.(uint64)

	}
	respUserInfo, _ := a.GetUserInfo(ctx, leaderId)
	if respUserInfo != nil {
		item["top_leader_id"] = respUserInfo.LeaderId
	}

	var (
		logType = "业务日志"
		logName = "创建用户"
		logMsg  string
	)

	defer func() {
		go func() {
			log.Info(fmt.Sprintf("创建用户 %+v", a.BusinessSrv.CreateBusinessRecord(ctx, uid, logType, logName, logMsg)))
			if v, ok := item["business_price_id"]; ok {
				log.Info(fmt.Sprintf("更新业务方案用户数量 %+v", a.UpdateBusinessPriceUserCount(ctx, v.(uint64), false)))
			}
		}()
	}()

	// 账号，密码不可以重复
	//if respUser, err := a.GetByAccountAndPasswd(ctx, item["account"].(string), item["passwd"].(string)); err == nil && respUser != nil {
	//	return errors.New(fmt.Sprintf("账号密码重复"))
	//}

	ids, err := a.getDefaultSieveSourceConfig()
	if err != nil {
		return err
	} else {
		item["business_type_ids"] = strings.Join(ids, "|")
	}

	item["passwd"] = GenPwdHash(item["passwd"].(string))
	_, err = a.UserRepo.Create(ctx, item)
	if err != nil {
		logType = "异常日志"
		logMsg = err.Error()
	}

	return err
}

func (a *UserSrv) GetRoleID(ctx context.Context, userId uint64) (uint64, error) {

	var (
		querySQL = fmt.Sprintf(`
		SELECT
			*
		FROM
		    user
		WHERE
		    id = %v AND deleted = 0
`, userId)
	)

	resp, err := a.UserRepo.QueryRaw(ctx, querySQL, user.User{})
	if err != nil {
		return 0, err
	}
	if len(resp) <= 0 {
		return 0, errors.New(fmt.Sprintf("no found such role by user_id:%+v", userId))
	}

	return resp[0].(*user.User).RoleId, nil
}

func (a *UserSrv) RoleJudge(req interface{}) interface{} {

	if req != nil {

		for i, v := range req.(map[string]interface{})["list"].([]interface{}) {

			resp := v.(*schemaCustomer.UserQueryRsp)
			req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.UserQueryRsp).IsAdmin = a.RoleSrv.IsAdminRoleId(uint64(resp.RoleId))
			req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.UserQueryRsp).IsSalespersonRole = a.RoleSrv.IsSalespersonRole(uint64(resp.RoleId))
			req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.UserQueryRsp).IsAgentRole = a.RoleSrv.IsAgentRole(uint64(resp.RoleId))
			req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.UserQueryRsp).IsChannelAgent = a.RoleSrv.IsChannelAgentRole(uint64(resp.RoleId))
		}
	}

	return req
}

func (a *UserSrv) addQueryResponseSeq(p schema.PaginationParam, req interface{}) interface{} {

	if req != nil {
		var enable bool
		if _, ok := req.(map[string]interface{})["total"]; ok {
			if _, ok := req.(map[string]interface{})["list"]; ok {
				enable = true
			}
		}

		if enable {
			var (
				indexStart = 1
				total      = req.(map[string]interface{})["total"].(uint64)
			)

			for i, _ := range req.(map[string]interface{})["list"].([]interface{}) {

				//resp := v.(*schemaCustomer.RechargeQueryRsp)
				seqNo := int(total) - (p.PageSize*(p.PageIndex-1) + (int(i) + 1)) + indexStart
				//seqNo := (p.PageSize*(p.PageIndex-1) + (int(i) + 1)) + autoIndexStart
				//req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.UserQueryRsp).Seq = int64(seqNo)
				req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.UserQueryRsp).SeqNo = int64(seqNo)
			}
		}
	}

	return req
}

func (a *UserSrv) Query(ctx context.Context, uid int, reqArgs map[string]interface{}, p schema.PaginationParam, args ...interface{}) interface{} {

	var (
		repKeys = []string{
			"user.id as id",
			"user.tag as tag",
			"user.account as account",
			"user.passwd as passwd",
			"user.business_price_id as business_price_id",
			"business_price_scheme.name as business_price_name",
			"business_price_scheme.description as business_price_desc",
			"user.business_type_ids as business_type_ids",
			"user.status as status",
			"user.role_id as role_id",
			"role.name as role_name",
			"role.alias as role_alias",
			"user.leader_id as leader_id",
			"user_leader.account as leader_name",
			"user.recharge_points as recharge_points",
			"user.bonus_points as bonus_points",
			"user.points_consume_account as points_consume_account",
			"user.points_consume_gift as points_consume_gift",
			"user.last_recharge as last_recharge",
			"user.last_consume as last_consume",
			"user.last_login as last_login",
			"user.create_at as create_at",
			"user.updated_at as updated_at",
			"user.deleted as deleted",
		}
		joinString = `
	LEFT JOIN business_price_scheme ON business_price_scheme.id = user.business_price_id and business_price_scheme.deleted = 0
	LEFT JOIN role ON role.id = user.role_id and role.deleted = 0
	LEFT JOIN (
		SELECT account,id FROM user WHERE user.deleted = 0 group by id,account
	) user_leader ON user_leader.id = user.leader_id`
	)

	condition := make(map[string]string)
	if _, ok := reqArgs["account"]; ok {

		condition["account"] = "LIKE"
		reqArgs["account"] = "'%" + reqArgs["account"].(string) + "%'"
	}

	roleId, err := a.GetRoleID(ctx, uint64(uid))
	if err != nil {
		return err
	}

	self := true
	if len(args) == 1 {
		self = args[0].(bool)
	}

	// 非管理员角色不可以看到自己
	if roleId != adminAccount.RoleId && !self {
		reqArgs["user.id"] = uid
		delete(reqArgs, "id")
		condition["user.id"] = "<>"

		var (
			cusSQL = fmt.Sprintf(`(user.leader_id = %v OR user.top_leader_id = %v)`, uid, uid)
		)

		ctx = context.WithValue(
			context.WithValue(ctx, "condition_customized", cusSQL),
			"group_by", "id")
	}

	if len(condition) > 0 {
		ctx = context.WithValue(ctx, "condition", condition)
	}

	ctx = context.WithValue(
		context.WithValue(ctx, "join", joinString),
		"column_types", schemaCustomer.UserQueryRsp{},
	)

	delete(reqArgs, "self")
	req, err := a.UserRepo.Query(ctx, reqArgs, p, repKeys)
	if err != nil {
		return err
	}

	return a.addQueryResponseSeq(p, a.RoleJudge(req))
}

func (a *UserSrv) QueryLeaders(ctx context.Context, uid int, item map[string]interface{}) interface{} {

	if v, ok := item["submit_type"]; !ok {
		return errors.New("请求参数错误")
	} else {
		if !(v.(uint64) == 1 || v.(uint64) == 2) {
			return errors.New("请求参数错误")
		}
		if v.(uint64) == 2 {
			if _, ok = item["will_role_id"]; !ok {
				return errors.New("请求参数错误")
			}
		}
	}

	respUser, err := a.GetByUID(ctx, uint64(uid))
	if err != nil && err.Error() != "record not  found" {
		return errors.New(fmt.Sprintf("获取用户信息失败:%+v", err))
	}

	type columnType struct {
		Id      int64  `json:"id"`
		Account string `json:"account"`
	}

	var (
		willRoleId    uint64
		condition     string
		roleCondition string
		//roleCondition  = "(user.leader_id = %v OR user.top_leader_id = %v)"
		querySQLFormat = `
			SELECT
			    user.leader_id as leader_id,
				user_leader.account as leader_name
			FROM 
			    user
			INNER JOIN (
				SELECT account,id FROM user WHERE user.deleted = 0 %v group by id,account
			) user_leader ON user_leader.id = user.leader_id
			WHERE user.deleted = 0 %v
			GROUP BY user.leader_id
		`
	)

	// submit_type = 1 表示搜索栏获取当前登录用户可以看到的用户列表的上级
	if item["submit_type"].(uint64) == 1 {

		var querySQL string
		if a.RoleSrv.IsAdminRoleId(respUser.RoleId) {
			querySQL = fmt.Sprintf(querySQLFormat, condition, roleCondition)
		} else {
			roleCondition = "AND (user.leader_id = %v OR user.top_leader_id = %v)"
			querySQL = fmt.Sprintf(querySQLFormat, condition, fmt.Sprintf(roleCondition, uid, uid))
		}

		respLeader, err := a.UserRepo.QueryRaw(ctx, querySQL, columnType{})
		if err != nil {
			return err
		}
		return respLeader
	}

	// 添加用户的时候，展示的上级
	/*

		1. 当角色为管理员时，可以创建业务员、代理商和渠道主账号，必须选择上级。
			业务员的上级下拉框：管理员，就是登陆的账号
			代理商的上级下拉框：当前登录账户可以在用户列表看到的业务员列表
			渠道主的上级下拉框：当前登录账户可以在用户列表看到的代理商和业务员列表,不包含管理员

		2. 当角色为业务员时，可以创建代理商和渠道主账号，默认上级为该业务员。
			业务员的上级下拉框：管理员，就是登陆的账号
			-- 没有上级下拉框

		3. 当角色为代理商时，只允许创建渠道主账号，默认上级为该代理商。
			-- 没有上级下拉框

		4. 当角色为渠道主时，没有用户管理页
	*/
	if item["submit_type"].(uint64) == 2 {

		willRoleId = item["will_role_id"].(uint64)
		//respUser, err := a.GetByUID(ctx, uint64(uid))
		//if err != nil && err.Error() != "record not  found" {
		//	return errors.New(fmt.Sprintf("获取用户信息失败:%+v", err))
		//}
		if respUser.RoleId != adminAccount.RoleId {
			return nil
		}

		if a.RoleSrv.IsSalespersonRole(willRoleId) {
			return []map[string]interface{}{
				{
					"id":      respUser.ID,
					"account": respUser.Account,
				},
			}
		}

		var querySQL string
		querySQLFormat = `SELECT id as leader_id,account as leader_name FROM user WHERE user.deleted = 0 %v group by id,account`
		if a.RoleSrv.IsAgentRole(willRoleId) {
			condition = fmt.Sprintf("AND user.role_id = %v", a.RoleSrv.GetSalespersonRole().ID)
			querySQL = fmt.Sprintf(querySQLFormat, condition)
		}

		if a.RoleSrv.IsChannelAgentRole(willRoleId) {

			condition = fmt.Sprintf("AND user.role_id IN (%v,%v) AND user.role_id <> %v", a.RoleSrv.GetSalespersonRole().ID, a.RoleSrv.GetAgentRole().ID, respUser.RoleId)
			querySQL = fmt.Sprintf(querySQLFormat, condition)
		}

		respLeader, err := a.UserRepo.QueryRaw(ctx, querySQL, columnType{})
		if err != nil {
			return err
		}
		return respLeader
	}

	return nil
}

func (a *UserSrv) QuerySieveConfig(ctx context.Context, uid uint64) interface{} {

	conditions := []string{
		fmt.Sprintf("business_type_configuration.status = 1"),
		fmt.Sprintf("business_type_configuration.deleted = 0"),
	}
	if uid != 0 {
		respUser, err := a.GetUserInfo(ctx, uint64(uid))
		if err != nil {
			return err
		}

		if respUser.BusinessTypeIds == "" {
			return nil
		}
		conditions = append(conditions, fmt.Sprintf("business_type_configuration.id IN (%v)", strings.Join(strings.Split(respUser.BusinessTypeIds, "|"), ",")))
	}

	var (
		querySQL = fmt.Sprintf(`
	SELECT 
	    IFNULL(sieve_source_config.label,"") as sieve_source_label,
	    IFNULL(sieve_source_config.name,"") as sieve_source_name,
	    IFNULL(sieve_source_config.alias,"") as sieve_source_alias,
	    IFNULL(sieve_source_config.default,0) as sieve_source_default,
	    IFNULL(sieve_source_config.status,0) as sieve_source_status,
	    IFNULL(business_type_configuration.sieve_source_config_id,0) as sieve_source_config_id,
	    business_type_configuration.name as business_type_name,
	    business_type_configuration.desc as business_type_desc,
	    business_type_configuration.unit_price as business_type_unit_price,
	    business_type_configuration.status as business_type_status,
	    business_type_configuration.role_id as business_type_role_id,
	    business_type_configuration.id as business_type_id
	FROM business_type_configuration
	INNER JOIN sieve_source_config ON business_type_configuration.sieve_source_config_id = sieve_source_config.id AND sieve_source_config.deleted = 0
	WHERE %v
`, strings.Join(conditions, " AND "))
	)

	req, err := a.SieveSourceConfigRepo.QueryRaw(ctx, querySQL, schemaCustomer.QuerySieveConfigRsp{})
	if err != nil {
		return err
	}

	if req == nil {
		return nil
	}

	type respType struct {
		Label    string                                `json:"Label"`
		Children []*schemaCustomer.QuerySieveConfigRsp `json:"children"`
	}
	itemMap := make(map[string][]*schemaCustomer.QuerySieveConfigRsp)
	for _, v := range req {
		item := v.(*schemaCustomer.QuerySieveConfigRsp)
		item.Label = fmt.Sprintf("%v(%v)", item.BusinessTypeName, item.BusinessTypeDesc)
		//itemMap[item.SieveSourceName] = append(itemMap[item.SieveSourceName], item)
		key := fmt.Sprintf("%v(%v)", item.SieveSourceLabel, item.SieveSourceAlias)
		itemMap[key] = append(itemMap[key], item)
	}

	var respTypeList []respType
	for k, v := range itemMap {
		respTypeList = append(respTypeList, respType{
			Label:    k,
			Children: v,
		})
	}

	return respTypeList
}

// 查询的是当前登录用户的下属用户的所有的角色
func (a *UserSrv) QueryRoles(ctx context.Context, uid int, reqArgs map[string]interface{}) interface{} {

	respUser, err := a.GetUserInfo(ctx, uint64(uid))
	if err != nil {
		return err
	}

	if respUser == nil {
		return nil
	}

	// submit_type = 1 表示返回角色的时候，不返回自身的角色
	var ignoreSelfRole bool
	if v, ok := reqArgs["submit_type"]; ok {
		ignoreSelfRole = v.(uint64) == 1
	}

	return a.RoleSrv.GetRoleList(ctx, uint64(respUser.RoleId), ignoreSelfRole)
}

func (a *UserSrv) queryRoles(ctx context.Context, uid int, reqArgs map[string]interface{}) interface{} {

	type columnType struct {
		RoleId    int64  `json:"role_id"`
		RoleName  string `json:"role_name"`
		RoleAlias string `json:"role_alias"`
	}

	var (
		repKeys = []string{"role.id as role_id", "role.name as role_name", "role.alias as role_alias"}
	)

	ctx = context.WithValue(ctx, "column_types", columnType{})

	req, err := a.RoleRepo.Query(ctx, reqArgs, schema.PaginationParam{}, repKeys)
	if err != nil {
		return err
	}
	return req
}

func (a *UserSrv) Enable(ctx context.Context, uid int, reqArgs map[string]interface{}) error {

	var (
		now        = time.Now().Unix()
		updateKeys = map[string]interface{}{
			"updated_at": now,
			"status":     1,
		}
		queryKeys = map[string]interface{}{
			"id": reqArgs["id"],
		}
	)

	resp, err := a.GetByUID(ctx, uint64(uid))
	if err != nil && err.Error() != "record not  found" {
		return errors.New(fmt.Sprintf("获取用户信息失败:%+v", err))
	}
	// 代理商没有 冻结/解冻权限
	if a.RoleSrv.IsAgentRole(resp.RoleId) {
		return errors.New("代理商没有冻结权限")
	}

	return a.UserRepo.Update(ctx, updateKeys, queryKeys)
}

func (a *UserSrv) Disable(ctx context.Context, uid int, reqArgs map[string]interface{}) error {

	var (
		now        = time.Now().Unix()
		updateKeys = map[string]interface{}{
			"updated_at": now,
			"status":     2,
		}
		queryKeys = map[string]interface{}{
			"id": reqArgs["id"],
		}
	)

	resp, err := a.GetByUID(ctx, uint64(uid))
	if err != nil && err.Error() != "record not  found" {
		return errors.New(fmt.Sprintf("获取用户信息失败:%+v", err))
	}
	// 代理商没有 冻结/解冻权限
	if a.RoleSrv.IsAgentRole(resp.RoleId) {
		return errors.New("代理商没有解冻权限")
	}

	return a.UserRepo.Update(ctx, updateKeys, queryKeys)
}

func (a *UserSrv) ResetPasswd(ctx context.Context, uid uint64, reqArgs map[string]interface{}) error {

	var (
		now        = time.Now().Unix()
		updateKeys = map[string]interface{}{
			"updated_at": now,
			"passwd":     GenPwdHash(reqArgs["passwd"].(string)),
		}
		queryKeys = map[string]interface{}{
			"id": reqArgs["id"],
		}
	)

	var (
		logType = "业务日志"
		logName = "修改密码"
		logMsg  string
	)

	defer func() {
		go func() {
			a.BusinessSrv.CreateBusinessRecord(ctx, uid, logType, logName, logMsg)
		}()
	}()

	err := a.UserRepo.Update(ctx, updateKeys, queryKeys)
	if err != nil {
		logType = "异常日志"
		logMsg = ""
	}

	return err
}

//func (a *UserSrv) DecreaseUserPoints(ctx context.Context, item map[string]interface{}) error {
//
//	var (
//		bp     = item["account_bonus_points"].(uint64)
//		cost   = item["will_tp"].(uint64)
//		rpCost uint64
//		bpCost = cost
//	)
//
//	if cost > bp {
//		bpCost = bp
//		rpCost = cost - bpCost
//	}
//
//	var (
//		updateSQL = fmt.Sprintf(`
//		UPDATE
//		    user
//		SET
//		    recharge_points = recharge_points - %v,
//		    bonus_points = bonus_points - %v
//		WHERE
//		    id = %v
//`, rpCost, bpCost, item["id"])
//	)
//
//	_, err := a.UserRepo.ExecRaw(ctx, updateSQL)
//	return err
//}

func (a *UserSrv) IncreaseUserPoints(ctx context.Context, id uint64, bp uint64, rp uint64) error {

	var (
		now       = time.Now().Unix()
		updateSQL = fmt.Sprintf(`
		UPDATE 
		    user 
		SET 
		    updated_at = %v,
		    recharge_points = recharge_points + %v,	
		    bonus_points = bonus_points + %v
		WHERE
		    id = %v
`, now, rp, bp, id)
	)

	_, err := a.UserRepo.ExecRaw(ctx, updateSQL)
	return err
}

func (a *UserSrv) DecreaseUserPoints(ctx context.Context, id uint64, bp uint64, rp uint64) error {

	var (
		now       = time.Now().Unix()
		updateSQL = fmt.Sprintf(`
		UPDATE 
		    user 
		SET 
		    updated_at = %v,
		    recharge_points = recharge_points - %v,	
		    bonus_points = bonus_points - %v
		WHERE
		    id = %v
`, now, rp, bp, id)
	)

	_, err := a.UserRepo.ExecRaw(ctx, updateSQL)
	return err
}

//
//func (a *UserSrv) DecreaseUserPoints(ctx context.Context, item map[string]interface{}) error {
//
//	var (
//		bp     = item["account_bonus_points"].(uint64)
//		cost   = item["will_tp"].(uint64)
//		rpCost uint64
//		bpCost = cost
//	)
//
//	if cost > bp {
//		bpCost = bp
//		rpCost = cost - bpCost
//	}
//
//	var (
//		updateSQL = fmt.Sprintf(`
//		UPDATE
//		    user
//		SET
//		    recharge_points = recharge_points - %v,
//		    bonus_points = bonus_points - %v
//		WHERE
//		    id = %v
//`, rpCost, bpCost, item["id"])
//	)
//
//	_, err := a.UserRepo.ExecRaw(ctx, updateSQL)
//	return err
//}

func (a *UserSrv) UpdateBatch(ctx context.Context, reqArgs map[string]interface{}) error {

	data := reqArgs
	for _, item := range strings.Split(data["id"].(string), "|") {
		reqArgs["id"] = item
		if err := a.Update(ctx, reqArgs); err != nil {
			log.Err(fmt.Sprintf("批量修改失败:%+v", item))
		}
	}

	return nil
}

func (a *UserSrv) checkBusinessTypeIDs(ctx context.Context, businessTypeIds string) error {

	var (
		dupMap = map[string]struct{}{}
	)

	var (
		querySQL = fmt.Sprintf(`
					SELECT
					 * 
					FROM 
					    business_type_configuration
					WHERE id IN (%v)
`, strings.Join(strings.Split(businessTypeIds, "|"), ","))
	)
	resp, err := a.SieveSourceConfigRepo.QueryRaw(ctx, querySQL, business_type.BusinessTypeConfiguration{})
	if err != nil {
		return err
	}
	for _, v := range resp {
		vv := v.(*business_type.BusinessTypeConfiguration)
		if _, ok := dupMap[vv.Name]; ok {
			return errors.New(fmt.Sprintf("相同的业务类型(%v)只能配置一个筛源", vv.Name))
		}
		dupMap[vv.Name] = struct{}{}
	}
	return nil
}

func (a *UserSrv) UpdateBusinessPriceUserCount(ctx context.Context, id uint64, isDel bool) error {

	op := "+"
	if isDel {
		op = "-"
	}
	var (
		execSQL = fmt.Sprintf(`
		UPDATE	
			business_price_scheme
		SET user_count = user_count %v 1
		WHERE id = %v
`, op, id)
	)

	_, err := a.BusinessPriceSchemeRepo.ExecRaw(ctx, execSQL)
	return err
}

func (a *UserSrv) updateBizPricesUserCount(ctx context.Context, uid uint64, reqArgs map[string]interface{}) error {

	if _, ok := reqArgs["business_price_id"]; !ok {
		return nil
	}

	newBizPriceId := reqArgs["business_price_id"].(uint64)
	var oldBizPriceId uint64
	if respUserInfo, _ := a.GetUserInfo(ctx, uid); respUserInfo != nil {
		oldBizPriceId = respUserInfo.BusinessPriceId
	}

	if newBizPriceId != oldBizPriceId && newBizPriceId != 0 && oldBizPriceId != 0 {
		if err := a.Trans.TransactionTx(ctx, func(ctx context.Context, t *mysql.Tx) error {

			if err := a.UpdateBusinessPriceUserCount(ctx, newBizPriceId, false); err != nil {
				return err
			}

			if err := a.UpdateBusinessPriceUserCount(ctx, oldBizPriceId, true); err != nil {
				return err
			}

			return nil
		}); err != nil {

			log.Err(fmt.Sprintf("更新价格配置用户数量失败:%+v", err))
		}
	}
	return nil
}

func (a *UserSrv) Update(ctx context.Context, reqArgs map[string]interface{}) error {

	var (
		now = time.Now().Unix()
		//updateKeys = map[string]interface{}{
		//	"updated_at":           now,
		//	"account":              reqArgs["account"],
		//	"role_id":              reqArgs["role_id"],
		//	"leader_id":            reqArgs["leader_id"],
		//	"sieve_source_configs": reqArgs["sieve_source_configs"],
		//	//"passwd":     GenPwdHash(reqArgs["passwd"].(string)),
		//}
		updateKeys = reqArgs
		queryKeys  = map[string]interface{}{
			"id": uint64(convert.Atoi(reqArgs["id"].(string))),
		}
	)
	if v, ok := reqArgs["id"]; ok {
		vv := strings.Split(v.(string), "|")
		if len(vv) > 1 {
			return a.UpdateBatch(ctx, reqArgs)
		}
	}

	if _, ok := reqArgs["id"]; !ok {
		return errors.New(fmt.Sprintf("'用户主键ID'为必填项"))
	}

	if _, ok := updateKeys["business_type_ids"]; ok {
		if fmt.Sprintf("%v", updateKeys["business_type_ids"]) != "empty" {
			if err := a.checkBusinessTypeIDs(ctx, updateKeys["business_type_ids"].(string)); err != nil {
				return err
			}
		}
	}

	delete(updateKeys, "id")
	updateKeys["updated_at"] = now

	if fmt.Sprintf("%v", updateKeys["business_type_ids"]) == "empty" {
		updateKeys["business_type_ids"] = ""
	}

	if _, ok := reqArgs["leader_id"]; ok {
		leaderId := reqArgs["leader_id"].(uint64)
		respUserInfo, _ := a.GetUserInfo(ctx, leaderId)
		if respUserInfo != nil {
			reqArgs["top_leader_id"] = respUserInfo.LeaderId
		}
	}

	err := a.updateBizPricesUserCount(ctx, queryKeys["id"].(uint64), reqArgs)
	if err != nil {
		return err
	}

	return a.UserRepo.Update(ctx, updateKeys, queryKeys)
}

func (a *UserSrv) GetAPIToken(ctx context.Context, reqArgs map[string]interface{}) interface{} {

	if _, ok := reqArgs["id"]; !ok {
		return errors.New("请求参数缺失")
	}
	respAccount, err := a.GetByUID(context.Background(), reqArgs["id"].(uint64))
	if err != nil {
		return err
	}

	gotToken := hash.SHA256([]byte(fmt.Sprintf("%v%v", respAccount.Account, respAccount.Passwd)))

	return gotToken
}

func (a *UserSrv) Delete(ctx context.Context, reqArgs map[string]interface{}) interface{} {

	var (
		id, _ = strconv.ParseUint(fmt.Sprintf("%v", reqArgs["id"]), 10, 64)
	)

	var oldBizPriceId uint64
	if respUserInfo, _ := a.GetUserInfo(ctx, reqArgs["id"].(uint64)); respUserInfo != nil {
		oldBizPriceId = respUserInfo.BusinessPriceId
	}

	return a.Trans.TransactionTx(ctx, func(ctx context.Context, t *mysql.Tx) error {

		if err := a.UpdateBusinessPriceUserCount(ctx, oldBizPriceId, true); err != nil {
			return err
		}

		return a.UserRepo.SoftDelete(ctx, id)
	})
}

func (a *UserSrv) GetUserLeaderSQL() string {
	return `
SELECT 
user.id,user_leader.id as leader_id,
(
	select account from user where id = user_leader.id
) as leader_account
FROM user
INNER JOIN
user user_leader ON user_leader.id = user.leader_id AND user_leader.deleted = 0
group by user.id
`
}

func (a *UserSrv) GetUserInfo(ctx context.Context, id uint64, args ...interface{}) (*schemaCustomer.UserQueryRsp, error) {

	var (
		reqArgs = map[string]interface{}{
			"id": id,
		}

		p = schema.PaginationParam{
			OnlyData: true,
		}
	)

	req := a.Query(ctx, int(id), reqArgs, p)
	if req != nil {
		if err, ok := req.(error); ok && err != nil {
			return nil, err
		}
	}

	var ret *schemaCustomer.UserQueryRsp
	for _, v := range req.(map[string]interface{})["list"].([]interface{}) {

		ret = v.(*schemaCustomer.UserQueryRsp)
		if len(args) == 1 && adminAccount.RoleId == uint64(ret.RoleId) {
			*args[0].(*bool) = true
		}
	}

	return ret, nil
}
